#include <stdio.h>
#include <pthread.h>
#include <sys/time.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include "gprmc.h"
#include "lvx_file.h"
#include "time_info.h"

int flag_exit_gps = 0;

u8 filename[30]={0};


//#define GPS_HEAD "$GPRMC"

#define GPRMC_HEAD "$GPRMC"

#define GPGGA_HEAD "$GPGGA"


#define GPS_HEAD GPGGA_HEAD


char path[100] = {0};

int init_libusb(void)
{
	/*1. init libusb lib*/
	int rv = 0;
	
	rv = libusb_init(NULL);
	if(rv < 0) {
		
		perror("\nInit libusb error");  
		return -1;
	}
	return rv;
}

int get_device_descriptor(struct libusb_device_descriptor *dev_desc,struct userDevice *user_device)
{
	/*2.get device descriptor*/
	int rv = -2;
	ssize_t cnt;
	int i = 0;
 
	libusb_device **devs;
	libusb_device *dev;
 
	cnt = libusb_get_device_list(NULL, &devs); //check the device number
	if (cnt < 0)
		return (int) cnt;
 
	while ((dev = devs[i++]) != NULL) {
		rv = libusb_get_device_descriptor(dev,dev_desc);
		if(rv < 0) {
			
			perror("\nlibusb_get_device_descriptor error");
			return -1;
		}
		if(dev_desc->idProduct==user_device->idProduct &&dev_desc->idVendor==user_device->idVendor)
		{
			user_device->dev = dev;
			user_device->devs = devs;
			rv = 0;
			printf("%04x:%04x\n",dev_desc->idProduct,dev_desc->idVendor);
			break;
		}
	}
	return rv;
}


void substring(char *des,char *str,int n,int index){
	char *p = des;
	char *q = str;
	int len = strlen(str);
	*(p++) = *(q);
	*(p++) = ',';
	if(n>len) n = len-index;
	if(index<0) index=0;
	if(index>len) return ;
	q += index;
	while(n--) *(p++) = *(q++);
	*(p++) = '\0';
	
}

void BCC(u8 *data,u8 *res){
	int len = strlen((char*)data);
	u8 checknum = '\0';
	int i=1;
	for(i=1;i<len-1;i++){
		checknum = checknum ^ data[i];
	}
	
	sprintf((char*)res,"%02x",checknum&0x00ff);
	
} 
int getMsTime(){
	struct timeval tv;
        gettimeofday(&tv,NULL);
        long ms = tv.tv_usec/1000;
	return ms;
}


void lenToHex(char *des,long len){
   
    des[0] = len&0x00ff;
    des[1] = (len>>8)&0x00ff;
    des[2] = (len>>16)&0x00ff;
    des[3] = (len>>24)&0x00ff;
    
}

void lock_set(int fd, int type)
{
    struct flock lock;
    lock.l_whence = SEEK_SET;//赋值lock结构体
    lock.l_start = 0;
    lock.l_len =0;
    while(1){
        lock.l_type = type;
        /*根据不同的type值给文件上锁或解锁*/
        if((fcntl(fd, F_SETLK, &lock)) == 0){
            if( lock.l_type == F_RDLCK )
            printf("read lock set by %d\n",getpid());
            else if( lock.l_type == F_WRLCK )
            printf("write lock set by %d\n",getpid());
            else if( lock.l_type == F_UNLCK )
            printf("release lock by %d\n",getpid());
            return;
        }
        /*判断文件是否可以上锁*/
        fcntl(fd, F_GETLK,&lock);
        /*判断文件不能上锁的原因*/
        if(lock.l_type != F_UNLCK){
            /*/该文件已有读取锁
            if( lock.l_type == F_RDLCK )
            printf("read lock already set by %d\n",lock.l_pid);
            */
            /*该文件已有写入锁*/
            if( lock.l_type == F_WRLCK )
                printf("write lock already set by %d\n",lock.l_pid);
            //getchar();
        }
    }
}

//*********************
extern
int getFileName(char *filename);
//{
//	
//	FILE *fp;
//	fp = fopen("filenameTemp.txt","rb+");
//  	while(fp==NULL){
//  		usleep(30);
//  		fp = fopen("filenameTemp.txt","rb+");
//  	} 
//  	
//	fscanf(fp,"%[^\n]", filename);
//	
//
//	printf("filename %s\n",filename);
//	fclose(fp);
//	return 1;;
//}
char str_gps_utc[32];
int flag_gps = 0;
extern volatile int rising_flag;
extern volatile int rising_time_refreshed;
extern char str_rise_time[64];
extern void savePackage_pps(char * str_in);

extern void SetRmcSyncTime(const char* rmc, uint16_t rmc_length);
void *saveToPackage1(void *arg){
}

void trim_tail(char * str_inout, char chr)
{
    int len = strlen(str_inout);
    char * p_tail = &str_inout[len-1];

    while(chr == * p_tail)
    {
       * p_tail = '\0';
       p_tail--;
    }
}

void *saveToPackage(void *arg){
	//int ms = getMsTime();	

	char buff_pps[64];
        if((rising_time_refreshed&0x01)==0)
        {
            return NULL;
        }
	
	u8 *GPRMC = (u8 *)arg;
        char * pDollar = strrchr((char *)GPRMC,'$');
        if(pDollar==NULL)
        {
            return NULL;
        }

        int gprmc_len = strlen((char*)pDollar);

        SetRmcSyncTime(pDollar,gprmc_len);
        memset(str_gps_utc,0,32);
        char * dot_p = strchr((char *)pDollar,'.');
        if(dot_p == NULL)
        {
            return NULL;
        }
    memcpy(str_gps_utc,dot_p-6,9);
        printf("utc time:%s\r\n",str_gps_utc);
    	sprintf(buff_pps,"$,%s,%s",str_gps_utc,str_rise_time);
    	
        if(rising_time_refreshed&0x08)
        {
           savePackage_pps(buff_pps);
           rising_time_refreshed = rising_time_refreshed&0x07;
        }
    	
    //flag_gps = 1;
	//printf("GPRMC %s\n",GPRMC);
	//char cms[12] = {0};

	char *temp_gprmc = (char *)malloc(gprmc_len*sizeof(u8)) ;
	memset(temp_gprmc,0,gprmc_len);
	char *s;
	char check[4];

	if (strstr((char *)GPRMC, GPGGA_HEAD))
	{
		char * pStar = strchr((char*)pDollar, '*');
		if (pStar)
		{
			memcpy(temp_gprmc, pDollar + 7, pStar - pDollar - 7);
		}
		else
		{
			memcpy(temp_gprmc, pDollar + 7, gprmc_len - 7);
		}

		trim_tail(temp_gprmc, ',');
	}
    else
    {
        if(strchr((char*)pDollar,'*'))
    	{
    	    substring(temp_gprmc,(char*)pDollar,gprmc_len-10,7);
    	}
    	else
    	{
    	    substring(temp_gprmc,(char*)pDollar,gprmc_len-7,7);
    	}
    }
	

	char runtime_str[24] = "2.034";
	g_run_duration->get_delta_str(runtime_str);

	
	
	//sprintf(cms,",%03d*",ms);
	temp_gprmc = (char *)realloc(temp_gprmc,(strlen(temp_gprmc)+strlen(runtime_str)+8)*sizeof(u8));
	//strcat(temp_gprmc,runtime_str);
        sprintf(temp_gprmc,"%s,%s",temp_gprmc,runtime_str);
	printf("%s\n",temp_gprmc);
	
	BCC((u8*)temp_gprmc,(u8*)check);
	
	//strcat(temp_gprmc,check);
        sprintf(temp_gprmc,"%s*%s",temp_gprmc,check);
	printf("%s\n bbc %s\n",temp_gprmc,check);
	
	//printf("size %d\n size %d\n ",strlen(GPRMC),strlen(temp_gprmc));
	int len = strlen(temp_gprmc);
	struct package *pk; 
	
	pk = (struct package *)malloc(sizeof(struct package));
	pk->gprmc = (u8 *)malloc(len*sizeof(u8));
	
	pk->header = 0x7B;
	pk->kind = 0x01;
	char *des = (char*)malloc(sizeof(char)*4);
	lenToHex(des,len);
	pk->length_07 = des[0];
	pk->length_815 = des[1];
	pk->length_1623 = des[2];
	pk->length_2431 = des[3];
	
	sprintf((char*)pk->gprmc,"%s",temp_gprmc);
	pk->tail1 = 0x0D;
	pk->tail2 = 0x0A;
	

	
//	FILE *fp;
//	fp = fopen(path,"ab+");
//	while(!fp){
//		usleep(30);
//		fp = fopen(path,"ab+");
//	}
        pthread_mutex_lock(&mutex_file_wr);
        write_to_lvx(&(pk->header),sizeof(pk->header),0);
        write_to_lvx(&(pk->kind),sizeof(pk->kind),0);
        write_to_lvx(&(pk->length_07),sizeof(pk->length_07),0);        
	write_to_lvx(&(pk->length_815),sizeof(pk->length_815),0);
	write_to_lvx(&(pk->length_1623),sizeof(pk->length_1623),0);
	write_to_lvx(&(pk->length_2431),sizeof(pk->length_2431),0);
	write_to_lvx(pk->gprmc,len,0);
	write_to_lvx(&(pk->tail1),sizeof(pk->tail1),0);
	write_to_lvx(&(pk->tail2),sizeof(pk->tail2),1);

        //fwrite(&(pk->header),sizeof(pk->header),1,fp);
	//fwrite(&(pk->kind),sizeof(pk->kind),1,fp);
	//fwrite(&(pk->length_07),sizeof(pk->length_07),1,fp);
	//fwrite(&(pk->length_815),sizeof(pk->length_815),1,fp);
	//fwrite(&(pk->length_1623),sizeof(pk->length_1623),1,fp);
	//fwrite(&(pk->length_2431),sizeof(pk->length_2431),1,fp);
	//fwrite(pk->gprmc,len,1,fp);
	//fwrite(&(pk->tail1),sizeof(pk->tail1),1,fp);
	//fwrite(&(pk->tail2),sizeof(pk->tail2),1,fp);
	pthread_mutex_unlock(&mutex_file_wr);
	free(temp_gprmc);
	free(pk->gprmc);
	free(pk);
	free(des);
//	fclose(fp);
	printf("write success\n");
        //rising_time_refreshed = rising_time_refreshed&0x06;//set bit0 and bit3 to 0
        //rising_time_refreshed = rising_time_refreshed&0x07;//set bit3 to 0
	/*
	int fd;
    fd = open(path,O_WRONLY | O_APPEND | O_CREAT,00777);
    while(fd < 0){
        usleep(30);
        fd = open(path,O_WRONLY | O_APPEND,00777);
    }
    lock_set(fd,F_WRLCK);
    write(fd,&(pk->header),sizeof(pk->header));
    write(fd,&(pk->kind),sizeof(pk->kind));
    write(fd,&(pk->length_07),sizeof(pk->length_07));
    write(fd,&(pk->length_815),sizeof(pk->length_815));
    write(fd,&(pk->length_1623),sizeof(pk->length_1623));
    write(fd,&(pk->length_2431),sizeof(pk->length_2431));
    write(fd,pk->gprmc,len);
    write(fd,&(pk->tail1),sizeof(pk->tail1));
    write(fd,&(pk->tail2),sizeof(pk->tail2));
    lock_set(fd,F_UNLCK);
    close(fd);
	free(temp_gprmc);
	free(pk->gprmc);
	free(pk);
	free(des);
	*/
}

void *saveToPackage2(void *arg){
	int ms = getMsTime();	

	char buff_pps[128];
	
	u8 *GPRMC = (u8 *)arg;
        int gprmc_len = strlen((char*)GPRMC);
        //memset(str_gps_utc,0,32);
        //char * dot_p = strchr((char *)GPRMC,'.');
    //memcpy(str_gps_utc,dot_p-6,9);

    //sprintf(buff_pps,"$,%s,%s",str_gps_utc,str_rise_time);

    //savePackage_pps(buff_pps);
    flag_gps = 1;
	printf("GPRMC %s\n",GPRMC);
	char cms[12] = {0};

	char temp_gprmc[128];// = (char *)malloc(gprmc_len*sizeof(u8)) ;
	memset(temp_gprmc,0,128);
	char *s;
	char check[32];
	
	substring(temp_gprmc,(char*)GPRMC,gprmc_len-7,7);

	char runtime_str[64];
        
	g_run_duration->get_delta_str(runtime_str);
printf("runtime_str in gps:%s\r\n",runtime_str);

	
	
	sprintf(cms,",%03d*",ms);
//free(temp_gprmc);

        int len_a = strlen(temp_gprmc)+strlen(runtime_str);
        printf("gps len_a=%d\r\n",len_a);

	//temp_gprmc = (char *)realloc(temp_gprmc,len_a*sizeof(u8));
	strcat(temp_gprmc,runtime_str);
	printf("gps temp_gprmc %s\n",temp_gprmc);
	
	BCC((u8*)temp_gprmc,(u8*)check);
	
	strcat(temp_gprmc,check);
	printf("%s\n bbc %s\n",temp_gprmc,check);
	
	//printf("size %d\n size %d\n ",strlen(GPRMC),strlen(temp_gprmc));
	int len = strlen(temp_gprmc);
	struct package *pk; 
	
	pk = (struct package *)malloc(sizeof(struct package));
	pk->gprmc = (u8 *)malloc(len*sizeof(u8));
	
	pk->header = 0x7B;
	pk->kind = 0x01;
	char *des = (char*)malloc(sizeof(char)*4);
	lenToHex(des,len);
	pk->length_07 = des[0];
	pk->length_815 = des[1];
	pk->length_1623 = des[2];
	pk->length_2431 = des[3];
	
	sprintf((char*)pk->gprmc,"%s",temp_gprmc);
	pk->tail1 = 0x0D;
	pk->tail2 = 0x0A;
	

	
//	FILE *fp;
//	fp = fopen(path,"ab+");
//	while(!fp){
//		usleep(30);
//		fp = fopen(path,"ab+");
//	}
        pthread_mutex_lock(&mutex_file_wr);
        write_to_lvx(&(pk->header),sizeof(pk->header),0);
        write_to_lvx(&(pk->kind),sizeof(pk->kind),0);
        write_to_lvx(&(pk->length_07),sizeof(pk->length_07),0);        
	write_to_lvx(&(pk->length_815),sizeof(pk->length_815),0);
	write_to_lvx(&(pk->length_1623),sizeof(pk->length_1623),0);
	write_to_lvx(&(pk->length_2431),sizeof(pk->length_2431),0);
	write_to_lvx(pk->gprmc,len,0);
	write_to_lvx(&(pk->tail1),sizeof(pk->tail1),0);
	write_to_lvx(&(pk->tail2),sizeof(pk->tail2),1);

        //fwrite(&(pk->header),sizeof(pk->header),1,fp);
	//fwrite(&(pk->kind),sizeof(pk->kind),1,fp);
	//fwrite(&(pk->length_07),sizeof(pk->length_07),1,fp);
	//fwrite(&(pk->length_815),sizeof(pk->length_815),1,fp);
	//fwrite(&(pk->length_1623),sizeof(pk->length_1623),1,fp);
	//fwrite(&(pk->length_2431),sizeof(pk->length_2431),1,fp);
	//fwrite(pk->gprmc,len,1,fp);
	//fwrite(&(pk->tail1),sizeof(pk->tail1),1,fp);
	//fwrite(&(pk->tail2),sizeof(pk->tail2),1,fp);
	pthread_mutex_unlock(&mutex_file_wr);
	//free(temp_gprmc);
	free(pk->gprmc);
        printf("free1\n");
	free(pk);
printf("free2\n");
	free(des);
printf("free3\n");
//	fclose(fp);
	printf("write success\n");
	/*
	int fd;
    fd = open(path,O_WRONLY | O_APPEND | O_CREAT,00777);
    while(fd < 0){
        usleep(30);
        fd = open(path,O_WRONLY | O_APPEND,00777);
    }
    lock_set(fd,F_WRLCK);
    write(fd,&(pk->header),sizeof(pk->header));
    write(fd,&(pk->kind),sizeof(pk->kind));
    write(fd,&(pk->length_07),sizeof(pk->length_07));
    write(fd,&(pk->length_815),sizeof(pk->length_815));
    write(fd,&(pk->length_1623),sizeof(pk->length_1623));
    write(fd,&(pk->length_2431),sizeof(pk->length_2431));
    write(fd,pk->gprmc,len);
    write(fd,&(pk->tail1),sizeof(pk->tail1));
    write(fd,&(pk->tail2),sizeof(pk->tail2));
    lock_set(fd,F_UNLCK);
    close(fd);
	free(temp_gprmc);
	free(pk->gprmc);
	free(pk);
	free(des);
	*/
}

void getGPS(unsigned short USB_PRODUCT_ID,unsigned short USB_VENDOR_ID){
	int rv;
 
	int length;
 
	unsigned char buf[32*15] = {0};
 
	libusb_device_handle* g_usb_handle;
 
	struct userDevice user_device;
	struct libusb_device_descriptor dev_desc;
 
	user_device.idProduct = USB_PRODUCT_ID;
	user_device.idVendor =  USB_VENDOR_ID ;
	user_device.bInterfaceClass = 0xff ;
	user_device.bmAttributes = 0x02 ; //03 中断 02 批量
	user_device.bInEndpointAddress = 0x82;
	user_device.bInterfaceNumber = 0;
	user_device.dev = NULL;
	FILE *fp;
	
	
	getFileName((char*)filename);
	
        sprintf(path,"/media/ubuntu/bae/%s/gps",filename);
	flag_exit_gps = 0;
 	while(!flag_exit_gps){
 		//初始化函数库
	 	init_libusb();
	 	//获取设备描述符
		rv = get_device_descriptor(&dev_desc,&user_device);
		if(rv < 0) {
				
			perror("\nget_device_descriptor error");
		}
	 	
		
		
		//打开设备
		g_usb_handle = libusb_open_device_with_vid_pid(NULL, user_device.idVendor, user_device.idProduct);
		if(g_usb_handle == NULL) {
			
			perror("\nopen_device error");
			sleep(1);
			
		}
	 
		rv = libusb_claim_interface(g_usb_handle,user_device.bInterfaceNumber);
		if(rv < 0) {
			rv = libusb_detach_kernel_driver(g_usb_handle,user_device.bInterfaceNumber);
			if(rv < 0) {
				
				perror("\ndetach_kernel_driver error"); 
				
			}
			rv = libusb_claim_interface(g_usb_handle,user_device.bInterfaceNumber);
			if(rv < 0)
			{
				
				perror("\nlibusb_claim_interface error");
				
			}
	 
		}
	 
	 	memset(buf,0,sizeof(buf));
		//buf[0] = '\0';
		rv = libusb_bulk_transfer(g_usb_handle,user_device.bInEndpointAddress,buf,sizeof(buf),&length,1000);	
		if(rv < 0) {
			printf("error code:%d\n",rv);
			perror("\nbulk_transfer error");
			
		}
	 	else{
	 		
	 		char *addr1 = strstr((char*)buf,(const char *)GPGGA_HEAD);
	 		if(addr1 == NULL)
	 		{
	 		    addr1 = strstr((char*)buf,(const char *)GPRMC_HEAD);
	 		}
			char *addr2 = strstr((char*)buf,"*");

			
			int len = addr2-addr1;
			printf("addr2-addr1 %d\n",len);
			printf("buf %s\n addr1 %s\n",buf,addr1);
			
			//if(buf[17]=='A'&&len>0){
				u8 *temp_buf = (u8 *)malloc((len+1)*sizeof(u8));
			
				memcpy(temp_buf,buf,sizeof(u8)*len);
				temp_buf[len] = '\0';
				printf("%s\n",temp_buf);
				//create pthread
				pthread_t id;
				int ret=0;
				int n=5;
				ret = pthread_create(&id,NULL,saveToPackage,(void*)temp_buf);
				printf("ret %d",ret);
				while(ret==-1&&n){
					
					perror("create pthread error");	
					usleep(100);
					printf("waiting for recreate");
					n--;	
					ret = pthread_create(&id,NULL,saveToPackage,(void*)temp_buf);	

				}

				pthread_join(id,NULL);
		 		free(temp_buf);
			//}

			
	 	}
			 	
		libusb_close(g_usb_handle);
	 
		libusb_release_interface(g_usb_handle,user_device.bInterfaceNumber);
	 
		libusb_free_device_list(user_device.devs, 1);
	 
		libusb_exit(NULL);
	
	}



}

void main_gps(void){

	getGPS(0x5523,0x1a86);


}





